package com.acme.chat.client;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

import com.acme.chat.message.Message;
import com.acme.chat.message.MessageType;
import com.acme.chat.newclient.ClientMessage;

// TODO: Refactor all this class
public class Client {
    private static final String ERROR_TOO_LONG_MESSAGE = "Your message is too long! Max allowed message size is " + Message.MAX_MESSAGE_LENGTH + " symbols.\n";

//    private ResourceBundle resourceFile = ResourceBundle.getBundle("resourceFile");

	private ObjectInputStream sInput;
	private ObjectOutputStream sOutput;
	private Socket socket;
	private ClientGUI cg;
	private String server;
	private String name;
	private int port;
	private String room;

	public Client(String server, int port, String room, String username) {
		this(server, port, room, username, null);
	}

	public Client(String server, int port, String room, String name, ClientGUI cg) {
		this.server = server;
		this.port = port;
		this.room = room;
		this.name = deleteWhitespaces(name);
		this.cg = cg;
	}

	private static String deleteWhitespaces(String username) {
		StringBuilder sb = new StringBuilder(username.trim());
		for (int i = 0; i < sb.length(); i++) {
			char v = sb.charAt(i);
			if (Character.isWhitespace(v)) {
				sb.deleteCharAt(i);
			}
		}
		return sb.toString();
	}

	public boolean start() {
		try {
			socket = new Socket(server, port);
		} catch (Exception e) {
		    display("Error connected to the server!\n");
//			display(resourceFile.getString("ErrorConnectToServer"));
			return false;
		}

		String msg = "Connection accepted " + socket.getInetAddress() + ":" + socket.getPort();
//		String msg = resourceFile.getString("ConnectionAccepted") + socket.getInetAddress() + ":" + socket.getPort();
		msg = msg + ", room: " + room + "\n";
		display(msg);

		try {
			sInput = new ObjectInputStream(socket.getInputStream());
			sOutput = new ObjectOutputStream(socket.getOutputStream());
		} catch (IOException e) {
			display("Exception creating new input/output streams!\n");
//			display(resourceFile.getString("ExceptionCreateIOStream"));
			return false;
		}

		try {
			sOutput.writeObject(name);
			sOutput.writeObject(room);
		} catch (IOException e) {
			display("Exception doing login!\n");
//			display(resourceFile.getString("ExcpLogin"));
			disconnect();
			return false;
		}
		new Client.ListenFromServer().start();
		return true;
	}

	private void display(String msg) {
		if (cg == null) {
			System.out.println(msg);
		} else {
			cg.append(msg);
		}
	}

    public boolean sendMessage(ClientMessage message) {
        try {
            if (message.getMessage().length() > Message.MAX_MESSAGE_LENGTH) {
                throw new IllegalArgumentException(ERROR_TOO_LONG_MESSAGE);
            }
            if ((message.getType() == MessageType.MESSAGE) && message.getMessage().isEmpty()) {
                return false;
            }
            sOutput.writeObject(message);
            return true;
        } catch (IOException e) {
            display("Exception writing to server.");
            return false;
        } catch (IllegalArgumentException e) {
            display(e.getMessage());
            return false;
        }
    }

    public void disconnect() {
		try {
			if (sInput != null) {
				sInput.close();
			}
		} catch (Exception e) {
		}
		try {
			if (sOutput != null) {
				sOutput.close();
			}
		} catch (Exception e) {
		}
		try {
			if (socket != null) {
				socket.close();
			}
		} catch (Exception e) {
		}
		if (cg != null) {
			cg.connectionFailed();
		}

	}

    public String getRoom() {
		return room;
	}

    public String getName() {
		return name;
	}

	private class ListenFromServer extends Thread {

		@Override
		public void run() {
			while (true) {
				try {
					Message message = (Message) sInput.readObject();
					if (cg == null) {
						System.out.println(message.getMessage());
						System.out.print("> ");
					} else {
						display(message.getMessage());
					}
				} catch (IOException e) {
					display("Server has close the connection.");
					if (cg != null) {
						cg.connectionFailed();
					}
					break;
				} catch (ClassNotFoundException e) {
				}
			}
		}
	}

    public boolean changeRoom(String room) {
        if (!this.room.equals(room)) {
            this.room = room;
            return true;
        }
        return false;
    }

}